use std::ops::Deref;


/// 词法分析器状态
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum LexerStage {
    /// start
    Start,
    /// abc...
    InId,
    /// 123...
    InNum,
    /// /?
    InDiv,
    /// /*...
    InComment,
    ///  ...*/
    EndComment,
    /// <?
    InLess,
    /// >?
    InGreater,
    /// =?
    InAssign,
    /// !?
    InNot,
    /// done
    Done,
}

/// 词法分析器的记号类别
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TokenType {
    // word
    Id,
    Number,

    // keyword
    Void,
    Int,
    If,
    Else,
    While,
    Return,

    // operator
    /// +
    Plus,
    /// -
    Minus,
    /// *
    Multiply,
    /// /
    Divide,
    /// <
    Less,
    /// <=
    LessEq,
    /// >
    Greater,
    /// >=
    GreaterEq,
    /// ==
    Eq,
    /// !=
    NotEq,
    // =
    Assign,
    /// ;
    Semicolon,
    /// ,
    Comma,
    /// (
    LeftRoundBracket,
    /// )
    RightRoundBracket,
    /// [
    LeftSquareBracket,
    /// ]
    RightSquareBracket,
    /// {
    LeftCurlyBracket,
    /// }
    RightCurlyBracket,
    /// "
    // DoubleQuote,
    /// '
    // SingleQuote,

    /// EOF
    EOF,

    // ast
    DeclList,
    VarDecl,
    FuncDecl,
    ParamList,
    Param,
    CompoundStmt,
    LocalDecl,
    StmtList,
    IfStmt,
    WhileStmt,
    ReturnStmt,
    Expr,
    Var,
    SimpleExpr,
    AddExpr,
    OpExpr,
    Term,
    Call,
    ArgList,
}

/// 保存记号的结构体
#[derive(Clone, Debug)]
pub struct Token {
    _token_type: TokenType,
    _token_str: Box<String>,
    _line_no: i32,
}

impl Token {
    pub fn new(token_type: TokenType, token_str: String, line_no: i32) -> Self {
        Self {
            _token_type: token_type,
            _token_str: Box::from(token_str),
            _line_no: line_no,
        }
    }
    pub fn token_type(&self) -> TokenType {
        return self._token_type;
    }
    pub fn line_no(&self) -> i32 {
        return self._line_no;
    }
    pub fn token_str(&self) -> Box<String> {
        return self._token_str.clone();
    }
    pub fn token_str_mut(&mut self) -> &mut String {
        return self._token_str.as_mut();
    }
}

impl Default for Token {
    fn default() -> Self {
        Self {
            _token_type: TokenType::EOF,
            _token_str: Box::new(String::default()),
            _line_no: 1,
        }
    }
}
